﻿using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Newtonsoft.Json;
using NPOI.SS.Formula.Functions;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Mozhi.Abp.Core.Networks
{
    public class DefaultRemoteServiceClient : IRemoteServiceClient
    {
        private readonly IConfiguration _configuration;

        private readonly IHttpClientFactory _httpClientFactory;

        private IHttpContextAccessor _httpContextAccessor;

        public DefaultRemoteServiceClient(IConfiguration configuration, IHttpContextAccessor httpContextAccessor, IHttpClientFactory httpClientFactory)
        {
            _configuration = configuration;
            _httpContextAccessor = httpContextAccessor;
            _httpClientFactory = httpClientFactory;
        }

        public async Task<T> GetAsync<T>(string serviceName, string url, bool useAccessToken = true)
        {
            var responseText = await SendRequestAsync(serviceName, url, HttpMethod.Get , useAccessToken);

            if (responseText.IsNullOrEmpty())
                return default;

            return JsonConvert.DeserializeObject<T>(responseText);
        }

        public async Task<RemotePageResult<T>> GetListAsync<T>(string serviceName, string url, bool useAccessToken = true)
        {
            var responseText = await SendRequestAsync(serviceName, url, HttpMethod.Get , useAccessToken);

            if (responseText.IsNullOrEmpty())
                return default;

            return JsonConvert.DeserializeObject<RemotePageResult<T>>(responseText);
        }

        public async Task<T> PostAysnc<T>(string serviceName, string url, T data, bool useAccessToken = true)
        {
            var responseText = await PostAsync(serviceName, url, data, useAccessToken);

            if (responseText.IsNullOrEmpty())
                return default;

            return JsonConvert.DeserializeObject<T>(responseText);
        }

        public async Task<T> PutAsync<T>(string serviceName, string url, bool useAccessToken = true)
        {
            var responseText = await SendRequestAsync(serviceName, url, HttpMethod.Put, useAccessToken);

            if (responseText.IsNullOrEmpty())
                return default;

            return JsonConvert.DeserializeObject<T>(responseText);
        }

        public async Task DeleteAsync(string serviceName, string url, bool useAccessToken = true)
        {
            await SendRequestAsync(serviceName, url, HttpMethod.Delete , useAccessToken);
        }

        #region
        private async Task<string> SendRequestAsync(string serviceName, string url, HttpMethod httpMethod , bool useAccessToken = true)
        {
            var host = _configuration[$"RemoteService:{serviceName}"];

            if (host.IsNullOrEmpty())
                throw new Exception($"RemoteService:{serviceName} 未配置");

            HttpRequestMessage requestMessage = new HttpRequestMessage(httpMethod, url);

            if (useAccessToken)
            {
                var accessToken = _httpContextAccessor.HttpContext.Request.Headers["authorization"];
                if (accessToken.ToString().IsNullOrEmpty())
                    throw new Exception("未登录");

                requestMessage.Headers.Add("Authorization", accessToken.ToString());
            }

            var result = string.Empty;

            var httpClient = _httpClientFactory.CreateClient();
            httpClient.BaseAddress = new Uri(host);

            var responseMessage = await httpClient.SendAsync(requestMessage);

            if (!responseMessage.IsSuccessStatusCode)

                throw new Exception($"connection fail：{url},status code :{responseMessage.StatusCode}");

            var repsonse = await responseMessage.Content.ReadAsStringAsync();

            return repsonse;
        }

        private async Task<string> PostAsync(string serviceName, string url, object data, bool useAccessToken = true)
        {
            var host = _configuration[$"RemoteService:{serviceName}"];

            if (host.IsNullOrEmpty())
                throw new Exception($"RemoteService:{serviceName} 未配置");

            StringContent content = null;

            if (data != null)
                content = new StringContent(JsonConvert.SerializeObject(data), Encoding.UTF8, "application/json");

            var result = string.Empty;

            var httpClient = _httpClientFactory.CreateClient();
            
            httpClient.BaseAddress = new Uri(host);

            if (useAccessToken)
            {
                var accessToken = _httpContextAccessor.HttpContext.Request.Headers["authorization"];
                if (accessToken.ToString().IsNullOrEmpty())
                    throw new Exception("未登录");

                var token = accessToken.ToString().Replace("Bearer ", "");

                httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
            }

            var responseMessage = await httpClient.PostAsync(url, content);

            if (!responseMessage.IsSuccessStatusCode)

                throw new Exception($"connection fail：{url},status code :{responseMessage.StatusCode}");

            var repsonse = await responseMessage.Content.ReadAsStringAsync();

            return repsonse;
        }
        #endregion
    }
}
